package com.polaris.live.im.sfs.processor.impl

import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.util.LogExt
import com.polaris.live.im.manager.ImGreetMessageManager
import com.polaris.live.im.manager.ImMessageManager
import com.polaris.live.im.manager.ImSessionManager
import com.polaris.live.im.sfs.COMMAND_BATCH_COMMAND
import com.polaris.live.im.sfs.COMMAND_BATCH_MESSAGE
import com.polaris.live.im.sfs.COMMAND_SINGLE_MESSAGE
import com.polaris.live.im.sfs.COMMAND_SYSTEM_MESSAGE
import com.polaris.live.im.sfs.TYPE_MESSAGE_INVITATION_ROOM
import com.polaris.live.im.sfs.TYPE_MESSAGE_NOTICE
import com.polaris.live.im.sfs.bean.chat.ReceiveBatchSingleMessage
import com.polaris.live.im.sfs.bean.chat.ReceiveSingleMessage
import com.polaris.live.im.sfs.bean.chat.UnreadSingleMessage
import com.polaris.live.im.sfs.core.SmartFoxConnector
import com.polaris.live.im.sfs.core.SmartFoxManager
import com.polaris.live.im.sfs.core.SmartFoxQueueManager
import com.polaris.live.im.sfs.core.bean.DataArgument
import com.polaris.live.im.sfs.core.bean.resolveResponse
import com.polaris.live.im.sfs.processor.ProceedMessageProcessSignal
import com.polaris.live.im.sfs.processor.impl.system.AbstractExcludeMessageProcessor
import com.polaris.live.im.utils.toMessageEntity
import com.polaris.live.im.utils.toSessionEntity
import com.polaris.live.utils.BitwiseUtils
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 私聊消息
 *
 * @author Created by lucas on 2023/10/19 16:43
 * @since 1.0.0
 */
class SingleMessageMessageProcessor : AbstractExcludeMessageProcessor() {

    override fun shouldProcess(type: Int, command: String): Boolean {
        return command in commands
    }

    override suspend fun handle(type: Int, command: String, argument: DataArgument) {
        when (command) {
            //收到私聊等消息
            COMMAND_SINGLE_MESSAGE, COMMAND_SYSTEM_MESSAGE -> {
                processSingleMessage(command, argument)
            }

            COMMAND_BATCH_MESSAGE -> {
                val batchMessage = argument.getData<ReceiveBatchSingleMessage>() ?: return
                processBatchSingleMessage(batchMessage)
            }
        }
    }

    /**
     * 获取未读的单聊消息
     */
    fun fetchUnreadSingleMessage(lastSeqId: Long? = null) {
        SmartFoxManager.messageScope.launch {
            try {
                do {
                    val response = SmartFoxQueueManager.sendChatMessage(
                        COMMAND_BATCH_COMMAND,
                        UnreadSingleMessage(lastSeqId),
                        timeout = TIMEOUT_BATCH_SEND
                    )

                    val batchMessage = response.receipt.resolveResponse<ReceiveBatchSingleMessage>()
                } while (batchMessage?.let { processBatchSingleMessage(it) } == true)
            } catch (t: Throwable) {
                LogExt.logE(SmartFoxManager.TAG, t)
            }
        }
    }

    /**
     * ================================================================处理实时收到的单条消息 分发消息
     */
    private fun processSingleMessage(command: String, argument: DataArgument) {
        val message = argument.getData<ReceiveSingleMessage>() ?: return

        //消息先保存到本地，完成后调用ack
        invokeProcessSingleMessage(command, message)
    }

    private fun invokeProcessSingleMessage(command: String, message: ReceiveSingleMessage) {
        SmartFoxManager.messageScope.launch {
            invokeSuspendProcessSingleMessage(command, message)
        }
    }

    private suspend fun invokeSuspendProcessSingleMessage(
        command: String,
        message: ReceiveSingleMessage,
    ) {
        withContext(SmartFoxManager.sendMessageDispatcher) {
            try {
                val messageEntity = message.toMessageEntity()

                ImMessageManager.insertMessage(messageEntity)

                if (messageEntity.command == COMMAND_SINGLE_MESSAGE) {
                    if (messageEntity.payloadBean?.flagGreetPushMessage == "1") {
                        ImGreetMessageManager.insertMessage(messageEntity)
                    }
                }

                //完成通知页面接收
                val action: suspend () -> Unit = {
                    ImMessageManager.onReceiveSingleMessage(message)
                }

                //通知消息不处理session
                if (!BitwiseUtils.isBitwise(message.type, TYPE_MESSAGE_NOTICE)) {
                    val requestSaveSession = message.toSessionEntity()
                    //房间邀请且是自己发送不添加红点
                    val isSelfSend = requestSaveSession.type?.let { messageType ->
                        if (BitwiseUtils.isBitwise(messageType, TYPE_MESSAGE_INVITATION_ROOM)) {
                            requestSaveSession.senderId == UserManager.getUserId()
                        } else {
                            false
                        }
                    } ?: false

                    //自己接收到服务器帮发的消息不添加红点
                    ImSessionManager.saveSession(
                        requestSaveSession,
                        isSelfSend
                    ) {
                        message.newSessionEntity = it

                        action()
                    }
                } else {
                    action()
                }
            } catch (t: Throwable) {
                LogExt.logE(SmartFoxManager.TAG, "receive", t)
            }
        }
    }

    private suspend fun processBatchSingleMessage(batchMessage: ReceiveBatchSingleMessage): Boolean {
        val messages = batchMessage.messages ?: emptyList()
        val hasMore = batchMessage.hasMore ?: false

        messages.forEach {
            val messageProcessSignal =
                exclude(SmartFoxConnector.CLIENT_CHAT, it.command, it.msgId, it.seqId)
            if (messageProcessSignal == ProceedMessageProcessSignal) {
                invokeSuspendProcessSingleMessage(it.command, it)
            }
        }

        val lastSeqId = messages.lastOrNull()?.seqId

        LogExt.logI(
            SmartFoxManager.TAG,
            "receive batch message ${messages.size} hasMore $hasMore lastSeqId $lastSeqId"
        )

        //如果还有数据继续请求
        return hasMore && lastSeqId != null
    }

    companion object {

        private const val TIMEOUT_BATCH_SEND = 60 * 1000L

        val commands = setOf(
            COMMAND_SINGLE_MESSAGE,
            COMMAND_SYSTEM_MESSAGE,
            COMMAND_BATCH_MESSAGE
        )
    }
}